import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;

public class Rectangle extends PhysicsObject {
	public float[] color = {0,0,1};
	private Vector2f[] vertices;
	
	private Vector2f[] vertexCache;
	private Vector2f[] normalCache;

	public Rectangle(float width, float height) {
		this(width, height, 1, true);
	}

	public Rectangle(float width, float height, float size, boolean pickable) {
		renderable = new Renderable(pickable);
		float halfheight = height * 0.5f * size;
		float halfwidth = width * 0.5f * size;
		vertices = new Vector2f[] {
				new Vector2f(-halfwidth, -halfheight),
				new Vector2f(-halfwidth, halfheight),
				new Vector2f(halfwidth, -halfheight),
				new Vector2f(halfwidth, halfheight)
		};
		centerOfMass = new Vector2f(0,0);
		renderable.CoMX = centerOfMass.x;
		renderable.CoMY = centerOfMass.y;
		double moi = Math.pow(size * width, 3) * height * size / 12;
		moi += Math.pow(size * height, 3) * width * size / 12;
		inverseMomentOfInertia = 1 / (float) moi;
	}
	
	public Vector2f[] getVertices() {
		if (vertexCache == null) {
			vertexCache = new Vector2f[vertices.length];
			Vector2f tmp = new Vector2f();
			for (int i = 0; i < vertices.length; i++) {
				tmp.x = vertices[i].x * renderable.scale;
				tmp.y = vertices[i].y * renderable.scale;
				tmp.sumScale(centerOfMass, -1);
				vertexCache[i] = new Vector2f();
				vertexCache[i].x = (float)(Math.cos(orientation) * tmp.x - Math.sin(orientation) * tmp.y);
				vertexCache[i].y = (float)(Math.sin(orientation) * tmp.x + Math.cos(orientation) * tmp.y);
				vertexCache[i].sum(centerOfMass);
				vertexCache[i].sum(position);
			}
		}
		return vertexCache;
	}
	
	public void clearCaches() {
		vertexCache = null;
		normalCache = null;
	}
	
	public CollisionInfo getRectangleCollision (PhysicsObject other) {
		if (other instanceof HalfSpace) {
			HalfSpace a = (HalfSpace) other;
			Vector2f[] vertices = this.getVertices();
			float[] distances = new float[vertices.length];

			for (int i = 0; i < vertices.length; i++)
				distances[i] = a.normal.dot(vertices[i]) - a.intercept;

			int minIndex = 0;
			for (int i = 1; i < distances.length; i++)
				if (distances[i] < distances[minIndex])
					minIndex = i;
			if (distances[minIndex] >= 0)
				return null;
			
			CollisionInfo cInfo = new CollisionInfo();
			cInfo.depth = -distances[minIndex];
			cInfo.normal = new Vector2f(a.normal);
			cInfo.positionA = new Vector2f(vertices[minIndex]);
			cInfo.positionA.sumScale(cInfo.normal, cInfo.depth);
			cInfo.positionB = new Vector2f(vertices[minIndex]);
			return cInfo;
		}
		return null;
	}

	private class Renderable extends SceneGraphNode {
		public Renderable(boolean pickable) {
			super(pickable);
			physics = Rectangle.this;
		}
		
		public void renderGeometry(GLAutoDrawable drawable) {
			GL2 gl = drawable.getGL().getGL2();
			gl.glColor3fv(color, 0);
			gl.glBegin(GL.GL_TRIANGLE_STRIP);
				for (Vector2f vert : vertices) {
					gl.glVertex2f(vert.x, vert.y);
				}
			gl.glEnd();
		}
	}
}
